package name.marz.to.go.ahg;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import name.marz.to.go.ahg.common.cli.OutDirOption;
import name.marz.to.go.ahg.common.cli.PasswordOption;
import name.marz.to.go.ahg.common.util.HttpUtil;
import name.marz.to.go.ahg.common.util.LogUtil;
import name.marz.to.go.ahg.core.AbstractAutoGetterMain;
import name.marz.to.go.ahg.core.AutoGetterHttpClient;
import name.marz.to.go.ahg.core.Parameters;
import name.marz.to.go.ahg.core.exception.InvalidDocumentException;
import name.marz.to.go.ahg.core.exception.UserProcessException;
import name.marz.to.go.ahg.core.executer.AbstractLoginExecuter;
import name.marz.to.go.ahg.core.executer.AbstractPostExecuter;
import name.marz.to.go.ahg.core.executer.DocumentGetExecuter;
import name.marz.to.go.ahg.core.executer.FileDownloadExecuter;
import name.marz.to.go.ahg.core.responsehandler.DocumentResponseHandler;
import name.marz.to.go.ahg.idemitsu.IdemitsuLoginExecuter;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;


public class IdemitsuGetMain extends AbstractAutoGetterMain {
	private static final Logger log = Logger.getLogger(IdemitsuGetMain.class.getName());
	private static final String DEFAULT_MEISAI_DIRNAME=".";
	
	private AutoGetterHttpClient client = new AutoGetterHttpClient();
	
	private String userId;
	private String password;
	private File outDir;
	
	private URI baseUri;
	/**
	 * 
	 */
	public IdemitsuGetMain() {
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		IdemitsuGetMain main = new IdemitsuGetMain();
		main.Main(args);
	}
	
	/* (non-Javadoc)
	 * @see name.marz.to.go.ahg.core.AbstractMain#ready()
	 */
	@Override
	protected void ready() throws Exception {
		super.ready();
		baseUri = HttpUtil.createURISafety("https://ws.idemitsucard.com/PC-IM/welcomeSCR.do");
	}
	
	@Override
	public Document goTopPage() throws ClientProtocolException, IOException,
			UserProcessException {
		Document doc;
		doc = new DocumentGetExecuter(baseUri, client,"TOP").execute();
		LogUtil.log(Level.FINE, client.getCookieStore().getCookies());
		LogUtil.log(Level.FINE, HttpUtil.getParametersFromFormTag(doc, "_USA01Form"),"top page form params");
		return doc;
	}

	@Override
	public Document doLogin(Document doc) throws ClientProtocolException, IOException, UserProcessException {
		AbstractLoginExecuter le = new IdemitsuLoginExecuter(baseUri, client, new String[] { userId },password,doc);
		doc = le.execute();
		log.finer("login response source="+doc.html());
		return doc;
	}

	@Override
	public Document goDownloadPage(Document doc)
			throws ClientProtocolException, IOException, UserProcessException {
		log.info("ご利用明細照会ページへ遷移開始");
		Elements e = doc.getElementsByAttributeValueContaining("alt", "ご利用明細照会");
		if ( e.size() == 0 ) throw new InvalidDocumentException("ご利用明細照会への遷移タグが見つかりません", doc);
		log.fine("image src="+e.first().outerHtml());
		log.fine("parent src="+e.first().parent().outerHtml());
		String anchor = e.first().parent().attr("href");
		if ( anchor == null ) throw new InvalidDocumentException("ご利用明細照会へのURLが見つかりません", doc);
		URI uri = HttpUtil.createURISafety(baseUri.getScheme(),baseUri.getAuthority(),anchor);
		DocumentGetExecuter de = new DocumentGetExecuter(uri, client);
		doc = de.execute();
		log.info("ご利用明細照会ページへ遷移終了");
		
		log.info("ご請求金額詳細ページへ遷移開始");
		anchor = HttpUtil.getFormActionString(doc, "_USC01Form");
		LogUtil.log(Level.FINER, HttpUtil.getParametersFromFormTag(doc, "_USC01Form"),"詳細ページ遷移用param");
		uri = HttpUtil.createURISafety(baseUri.getScheme(),baseUri.getAuthority(),anchor);
		final Document ddoc = doc;
		AbstractPostExecuter<Document> pe = new AbstractPostExecuter<Document>(uri,client) {
			private static final String FORM_NAME = "_USC01Form";
			private ResponseHandler<Document> handler;
			@Override
			protected List<NameValuePair> getRequestParameters() {
				Parameters p = HttpUtil.getParametersFromFormTag(ddoc, FORM_NAME);
				String submitName = getSubmitName(p);
				if ( submitName == null ) throw new InvalidDocumentException("'submit' not found ", ddoc);
				List<NameValuePair> params = new ArrayList<NameValuePair>();
				params.add(p.getNameValuePair(submitName));
				params.add(p.getNameValuePair("t"));
				params.add(p.getNameValuePair("forward_NATOP"));
				params.add(p.getNameValuePair("forward_USC0103BLP01"));
				params.add(p.getNameValuePair("org.apache.struts.taglib.html.TOKEN"));
				return params;
			}

			private String getSubmitName(Parameters p) {
				for (String s : p.keySet()) {
					if ( s.startsWith("forward_USC0102BLC01_targetMonthDiv=") ) {
						return s;
					}
				}
				return null;
			}

			@Override
			protected ResponseHandler<Document> getResponseHandler() {
				 if ( handler == null ) {
					 handler = new DocumentResponseHandler(client.getDefaultCharset());
				 }
				return handler;
			}
		};
		doc = pe.execute();
		log.finer("response source="+doc.html());
		
		log.info("ご請求金額詳細ページへ遷移終了");
		
		return doc;
	}

	@Override
	public File doDownload(Document doc) throws ClientProtocolException,
			IOException, UserProcessException {
		// 口座の詳細ページへのURLを取得
		Elements e = doc.getElementsContainingOwnText("CSVダウンロード");
		if ( e.size() == 0 ) throw new InvalidDocumentException("CSVダウンロードのタグが見つかりません", doc);
		log.fine("element src="+e.first().outerHtml());
		log.fine("parent src="+e.first().parent().outerHtml());
		String anchor = e.first().parent().attr("href");
		if ( anchor == null ) throw new InvalidDocumentException("CSVダウンロードのURLが見つかりません", doc);
		URI uri = HttpUtil.createURISafety(baseUri.getScheme(),baseUri.getAuthority(),anchor);
		FileDownloadExecuter fe = new FileDownloadExecuter(uri, client, outDir);
		return fe.execute();
	}

	@Override
	public void doLogout(Document doc) throws ClientProtocolException,
			IOException, UserProcessException {
		// ログアウトタグからログアウト用URLを取り出す
		final String LOGOUT_ID="ログアウト";
		Elements e = doc.getElementsByAttributeValue("alt",LOGOUT_ID);
		if ( e.size() == 0 ) throw new IllegalStateException("alt "+LOGOUT_ID+"が見つかりません");
		Element a = e.first().parent();
		log.fine("logout a src="+a.outerHtml());
		if ( !a.tag().getName().equals("a") ) throw new IllegalStateException("ログアウト用のaタグが見つかりません");
		String anchor = a.attr("href");
		URI uri = HttpUtil.createURISafety(baseUri.getScheme(),baseUri.getAuthority(),anchor);
		DocumentGetExecuter executer = new DocumentGetExecuter(uri, client, "logout");
		Document d = executer.execute();
		log.finest("logout response="+d.html());
		
	}

	/* (non-Javadoc)
	 * @see name.marz.to.go.ahg.core.AbstractMain#finish()
	 */
	@Override
	protected void finish() {
		super.finish();
		// 終了処理
		client.getConnectionManager().shutdown();
	}
	
	@SuppressWarnings("static-access")
	@Override
	protected Options getOptions() {
		Options options = new Options();
		Option out = new OutDirOption(false);options.addOption(out);
		options.addOption(OptionBuilder.hasArg(true).withArgName("login id")
				.isRequired(true).withDescription("ログインID")
				.create("id"));
		Option password = new PasswordOption(true); options.addOption(password);
		return options;
	}

	@Override
	protected void setParams(CommandLine cmd) {
		userId = cmd.getOptionValue("id");
		this.password = cmd.getOptionValue(PasswordOption.OPT);
		outDir = new File(cmd.getOptionValue(OutDirOption.OPT, DEFAULT_MEISAI_DIRNAME));
	}
}
